package com.cyj.springbootservice.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cyj.springbootservice.api.entity.PostInfo;
import com.cyj.springbootservice.mapper.PostInfoMapper;
import com.cyj.springbootservice.service.PostInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.context.WebServerInitializedEvent;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.data.geo.Circle;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoResult;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Metrics;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * @description:
 * @Author C_Y_J
 * @create 2021/10/13 10:18
 **/
@Slf4j
@Configuration
@Service
public class PostInfoServiceImpl extends ServiceImpl<PostInfoMapper, PostInfo> implements PostInfoService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    private final static String KEY = "post_info";


    @Async
    @Order
    @EventListener({WebServerInitializedEvent.class})
    public void initRoute() {
        redisTemplate.delete(KEY);
        log.info("开始初始化帖子信息");

        this.list().forEach(
                postInfo -> {
                    log.info("加载路由ID：{},{}", postInfo.getId(), postInfo);
                    redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(PostInfo.class));
                    redisTemplate.opsForGeo().add(
                            KEY,
                            new RedisGeoCommands.GeoLocation<>(
                                    postInfo.getId(),
                                    new Point(postInfo.getLongitude(), postInfo.getLatitude())
                            )
                    );
                }
        );
    }

    @Override
    public boolean submit(PostInfo postInfo) {
        this.save(postInfo);

        redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(PostInfo.class));
        Long flag = redisTemplate.opsForGeo().add(
                KEY,
                new RedisGeoCommands.GeoLocation<>(
                        postInfo.getId(),
                        new Point(postInfo.getLongitude(), postInfo.getLatitude())
                )
        );
        return flag != null && flag > 0;

    }

    /**
     * @param distance      距离范围 单位km 可根据{@link org.springframework.data.geo.Metrics} 进行设置
     * @param userLongitude 当前经度
     * @param userLatitude  当前纬度
     * @return
     */
    @Override
    public List<PostInfo> nearBySearch(double distance, double userLongitude, double userLatitude) {

        List<PostInfo> postInfoList = new ArrayList<>();

        GeoResults<RedisGeoCommands.GeoLocation<Object>> result = redisTemplate.opsForGeo().radius(
                KEY,
                new Circle(
                        new Point(userLongitude, userLatitude),
                        new Distance(distance, Metrics.KILOMETERS)
                ),
                RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates().sortAscending()
        );

        assert result != null;

        List<GeoResult<RedisGeoCommands.GeoLocation<Object>>> content = result.getContent();

        content.forEach(
                a -> postInfoList.add(
                        new PostInfo()
                                .setDistance(a.getDistance().getValue())
                                .setLatitude(a.getContent().getPoint().getX())
                                .setLongitude(a.getContent().getPoint().getY())
                )
        );

        return postInfoList;
    }
}